今天我們要深入探討 React 的渲染機制 (Render Phase)。理解組件何時會重新渲染(Re-render),是避免不必要效能浪費、解決畫面死鎖與掌握 React 生命週期的重要關鍵。
在 React 中,Render 不等於「畫面直接重繪」。一次完整的 UI 更新包含以下三個階段:
Trigger(觸發):產生更新需求(例如使用者點擊按鈕)。
Render(計算):React 呼叫組件函數,計算新的 Virtual DOM 樹,並透過 Diffing 演算法比對前後差異。
Commit(提交):React 將計算好的最小差異實際寫入真實 DOM,隨後瀏覽器繪製畫面。
一個 React 組件會觸發 Re-render,歸根究底只有以下三大原因:
┌─────────────────────────┐
│ 1. State 發生變更 │
├─────────────────────────┤
觸發 Re-render ───► │ 2. Parent 重新渲染 │
├─────────────────────────┤
│ 3. Context 數值改變 │
└─────────────────────────┘
const [count, setCount] = useState(0);
// 點擊後 count 改變,觸發內部 Re-render
<button onClick={() => setCount(count + 1)}>加一</button>
注意:如果呼叫 setCount(0) 傳入相同的值,React 會自動跳過 (Bailout) 渲染。
function Parent() {
const [theme, setTheme] = useState('light');
return (
<div>
{/* 當 Parent 因為 theme 改變而 Re-render */}
{/* Child 組件就算沒帶任何 Props,也會無條件跟著 Re-render! */}
<Child />
</div>
);
}
解決方案:若子組件渲染成本極高且 Props 沒變,可使用 React.memo 進行快取優化。
許多教學會寫「觸發 Re-render 的時機:State 變更、Props 變更、Context 變更」,這其實是不夠精確的誤導!
真實情況:Props 本身無法主動觸發 Re-render。
Props 是由父組件傳入的。父組件為了傳送新的 Props,父組件自己必須先 Re-render。因此,子組件是因為「父組件重新渲染」而被連帶觸發渲染,進而接收到新的 Props,而不是 Props 自己引發了 Re-render!